/***
 * * PROJECT
 * *    ATaG
 * * VERSION
 * *    $Revision: 1.14 $
 * * DATE
 * *    $Date: 2009/06/19 11:57:49 $
 * * LOG
 * *    $Log: ATaGParser.java,v $
 * *    Revision 1.14  2009/06/19 11:57:49  animesh
 * *    removed validation from XML
 * *
 * *    Revision 1.13  2008/10/07 12:57:37  animesh
 * *    removed GPL License [will re-add to all files later]
 * *
 * *    Revision 1.12  2007/08/24 07:41:25  animesh
 * *    edited to conform to the updated XML format.
 * *
 * *    Revision 1.11  2007/06/01 20:53:20  animesh
 * *    bulk update.
 * *
 * *    Revision 1.10  2007/01/27 02:49:53  animesh
 * *    fixed an error due to accessing wrong element of the array of attributes in the neededAttribute tag.
 * *
 * *    Revision 1.9  2006/12/19 02:19:19  animesh
 * *    Updated to support a larger set of annotations. Works with traffic.xml now.
 * *
 * *    Revision 1.8  2006/10/26 00:19:59  animesh
 * *    set all periodic tasks to run at init by default. Need to fix later.
 * *
 * *    Revision 1.7  2006/10/25 22:32:55  animesh
 * *    changed ATaGChannelDeclaration to ScopedChannel
 * *
 * *    Revision 1.6  2006/10/25 22:11:30  animesh
 * *    added @returns to the Parser
 * *
 * *    Revision 1.5  2006/10/21 00:17:54  animesh
 * *    no message
 * *
 * *    Revision 1.4  2006/10/19 22:18:32  animesh
 * *    *** empty log message ***
 * *
 * *    Revision 1.3  2006/10/19 21:21:53  lmottola
 * *    Added CVS preamble.
 * *
 * *
 * *   ATaG (Abstract Task Graph) - Data-driven Macroprogramming for
 * *                                Sensor Networks
 * *
 ***/

package atag.compiler;

import atag.common.ScopedChannel;
import atag.common.ATaGDataItemDeclaration;
import atag.common.ATaGProgram;
import atag.common.ATaGTaskDeclaration;

import atag.runtime.ln.nodeAttributes.SetAttribute;

import java.util.*;
// for xml stuff
import javax.xml.parsers.*;

import org.xml.sax.*;

import java.io.*;

import org.w3c.dom.*;

/**
 * ATaGParser is a utility class that parses an ATaG program written in XML
 * using schemas for validation
 * The main function returns a structure ATaGProgram with all data filled in,
 * or returns zero.
 *
 * @author Animesh
 * @author Ajay Chhatwal
 */
public class ATaGParser {

    // Global value so it can be ref'd by the tree-adapter
    static Document document;
    
    private static HashMap<String,String> javaDataTypeFromXmlType;
    
    static
    {        
        javaDataTypeFromXmlType= new HashMap<String, String>();
        javaDataTypeFromXmlType.put("xs:integer", "int");
        javaDataTypeFromXmlType.put("xs:decimal", "double");
        javaDataTypeFromXmlType.put("xs:string", "String");    
    }
    /**
     * Creates a new instance of ATaGParser
     */
    public ATaGParser() {            
    }


    /**
     * prints node and all its subnodes.
     */
    static void print(Node node, PrintStream out) {
        int type = node.getNodeType();
        switch (type) {
            case Node.ELEMENT_NODE:
                out.print("<" + node.getNodeName());
                NamedNodeMap attrs = node.getAttributes();
                int len = attrs.getLength();
                for (int i = 0; i < len; i++) {
                    Attr attr = (Attr) attrs.item(i);
                    out.print(" " + attr.getNodeName() + "=\"" +
                            escapeXML(attr.getNodeValue()) + "\"");
                }
                out.print('>');
                NodeList children = node.getChildNodes();
                len = children.getLength();
                for (int i = 0; i < len; i++)
                    print(children.item(i), out);
                out.print("</" + node.getNodeName() + ">");
                break;
            case Node.ENTITY_REFERENCE_NODE:
                out.print("&" + node.getNodeName() + ";");
                break;
            case Node.CDATA_SECTION_NODE:
                out.print("<![CDATA[" + node.getNodeValue() + "]]>");
                break;
            case Node.TEXT_NODE:
                out.print(escapeXML(node.getNodeValue()));
                break;
            case Node.PROCESSING_INSTRUCTION_NODE:
                out.print("<?" + node.getNodeName());
                String data = node.getNodeValue();
                if (data != null && data.length() > 0)
                    out.print(" " + data);
                out.println("?>");
                break;
        }
    }

    static String escapeXML(String s) {
        StringBuffer str = new StringBuffer();
        int len = (s != null) ? s.length() : 0;
        for (int i = 0; i < len; i++) {
            char ch = s.charAt(i);
            switch (ch) {
                case '<':
                    str.append("&lt;");
                    break;
                case '>':
                    str.append("&gt;");
                    break;
                case '&':
                    str.append("&amp;");
                    break;
                case '"':
                    str.append("&quot;");
                    break;
                case '\'':
                    str.append("&apos;");
                    break;
                default:
                    str.append(ch);
            }
        }
        return str.toString();
    }


    /**
     * Function to print tree form given a document
     *
     * @param filename The name of the XML file for parsing
     *                 The file should contain the ATaG Code
     * @returns the ATaGProgram corresponding to the data in the file
     */
/*
    private static void printTree(Document doc){
        try{
            Node n = doc.getDocumentElement();
            PrintStream out = System.out;
            //out.println("<?xml version=\"1.0\"?>");
            //print(n, out);
            parseATaGXML(n,out);
 
        } catch (Exception e) {e.printStackTrace();}
 
    }
 */
    /*
    private static void printTree (Document doc){
        try{
            Node n = doc.getDocumentElement().getFirstChild();
                PrintStream out = System.out;
                out.println("<?xml version=\"1.0\"?>");
     
                while (n!=null){
                    print(n, out);
                    n = n.getNextSibling();
                }
        } catch (Exception e) {e.printStackTrace();}
     
    }
     */

    /*
   private static void printTree (Document doc){
       try{
           Node n = doc.getDocumentElement().getFirstChild();
           while (n!=null && !n.getNodeName().equals("recipe"))
               n = n.getNextSibling();
           PrintStream out = System.out;
           out.println("<?xml version=\"1.0\"?>");
           out.println("<collection>");
           if (n!=null)
               print(n, out);
           out.println("</collection>");
       } catch (Exception e) {e.printStackTrace();}

   }


    */

    /*
    public static ATaGProgram parseATaGProgram(String filename){
       throw new UnsupportedOperationException("This is not supported");
      }

    */


    /**
     * @param filename The name of the XML file for parsing
     * The file should contain the ATaG Code
     * @returns the ATaGProgram corresponding to the data in the file
     */
    public static ATaGProgram parseATaGProgram(String filename) {

        DocumentBuilderFactory factory =
                DocumentBuilderFactory.newInstance();
        factory.setValidating(false);
        //factory.setValidating(true);
        //factory.setNamespaceAware(true);

        ATaGProgram retProgram = new ATaGProgram();

        try {
            DocumentBuilder builder = factory.newDocumentBuilder();

            ATaGParsingErrorHandler eh = new ATaGParsingErrorHandler();

            builder.setErrorHandler(eh);

            /*
            use the info in http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JAXPDOM8.html
            */
            document = builder.parse(new File(filename));


            // now do stuff with it
            try {
                Node n = document.getDocumentElement();
                retProgram = parseATaGXML(n);

            } catch (Exception e) {
                e.printStackTrace();
            }


        } catch (SAXException sxe) {
            // Error generated during parsing)
            Exception x = sxe;
            if (sxe.getException() != null)
                x = sxe.getException();
            x.printStackTrace();
            /*
            System.out.println("Parsing failed. Document does not match DTD");
             */

        } catch (ParserConfigurationException pce) {
            // Parser with specified options can't be built
            pce.printStackTrace();

        } catch (IOException ioe) {
            // I/O error
            ioe.printStackTrace();
        }

        return retProgram;
    } // main


    static ATaGProgram parseATaGXML(Node node) {

        boolean debug = true;//change accordingly

        PrintStream out = System.out;

        ATaGProgram retProgram = new ATaGProgram();

        //assuming we got the main XML atagprogram node

        String mainname = node.getNodeName();
        if (debug)
            out.println("The main node is " + mainname);

        NodeList topLevelChildren = node.getChildNodes();
        int numberOfTopLevelChildren = topLevelChildren.getLength();

        if (debug)
            out.println("The number of top level children is "
                    + numberOfTopLevelChildren + " and the non-text elements are..");


        int count = 0;

        //skip text type child nodes
        while (topLevelChildren.item(count).getNodeType() != Node.ELEMENT_NODE)
            count++;

        Node taskList = topLevelChildren.item(count++);
        if (debug)
            out.println(taskList.getNodeName());

        // now populate the task list
        ArrayList<ATaGTaskDeclaration> tList = retProgram.getTaskList();

        NodeList taskListChildren = taskList.getChildNodes();
        String namespace;
        for (int taskCount = 0; taskCount < taskListChildren.getLength(); taskCount++) {
            Node tempTaskNode = taskListChildren.item(taskCount);
            if (tempTaskNode.getNodeType() != Node.ELEMENT_NODE) {
                //plain text. Ignore
                continue;
            } else {
                //other node. this is a task
                ATaGTaskDeclaration newTask = new ATaGTaskDeclaration();
                //fill in the details
                NamedNodeMap taskAttrs = tempTaskNode.getAttributes();
                int len = taskAttrs.getLength();
                for (int i = 0; i < len; i++) {
                    Attr attr = (Attr) taskAttrs.item(i);
                    if (debug)
                        out.println("Attr #" + i + " " + attr.getNodeName() + " is " +
                                attr.getNodeValue());
                }

                newTask.setName(new String(taskAttrs.item(0).getNodeValue()));

                //now set firingrule
                NodeList childrenOfTask = tempTaskNode.getChildNodes();
                //advance the pointer for text nodes
                Node firingRuleNode = childrenOfTask.item(0);
                while (firingRuleNode.getNodeType() != Node.ELEMENT_NODE)
                    firingRuleNode = firingRuleNode.getNextSibling();
                //this is the real firing rule
                if (debug)
                    out.println(firingRuleNode.getNodeName());
                //and now traverse the tree of the firingRule
                NodeList childrenOfFiringRule = firingRuleNode.getChildNodes();
                Node actualFiringRuleNode = childrenOfFiringRule.item(0);
                //jumping over plain text nodes
                while (actualFiringRuleNode.getNodeType() != Node.ELEMENT_NODE)
                    actualFiringRuleNode = actualFiringRuleNode.getNextSibling();
                String firingRuleType = actualFiringRuleNode.getNodeName();

                if (debug)
                    out.println(firingRuleType);

                int[] tempFiringRule = new int[2];
                boolean runAtInit = false;
                if (firingRuleType.equals("extern")) {
                    tempFiringRule[0] = ATaGTaskDeclaration.FIRING_EXTERN;
                    tempFiringRule[1] = 0;//just like that                    
                }
                if (firingRuleType.equals("anydata")) {
                    tempFiringRule[0] = ATaGTaskDeclaration.FIRING_ANYDATA;
                    tempFiringRule[1] = 0;//just like that
                }
                if (firingRuleType.equals("triggered")) {
                    tempFiringRule[0] = ATaGTaskDeclaration.FIRING_TRIGGERED;
                    tempFiringRule[1] = 0;//just like that
                    runAtInit = true; // If its GUI task then we set it to false later
                } else if ((firingRuleType.equals("alldata"))) {
                    tempFiringRule[0] = ATaGTaskDeclaration.FIRING_ALLDATA;
                    tempFiringRule[1] = 0; //just like that
                } else if ((firingRuleType.equals("periodic"))) {
                    tempFiringRule[0] = ATaGTaskDeclaration.FIRING_PERIODIC;
                    // set to run at init
                    // TODO change this to read a parameter, not just make periodic ones
                    runAtInit = true;
                    //set period as the other element
                    tempFiringRule[1] = Integer.parseInt(
                            actualFiringRuleNode.getAttributes().item(0).getNodeValue());
                    if (debug)
                        out.println(tempFiringRule[1]);
                }

                newTask.setFiringRule(tempFiringRule);
                newTask.setRunAtInit(runAtInit);
                //now for the Location

                Node taskLocationNode = firingRuleNode.getNextSibling();
                while (taskLocationNode.getNodeType() != Node.ELEMENT_NODE)
                    taskLocationNode = taskLocationNode.getNextSibling();
                //this is the real task location
                if (debug)
                    out.println(taskLocationNode.getNodeName());
                if(newTask.getFiringRule()[0]==ATaGTaskDeclaration.FIRING_EXTERN)
                {
                    String url,serviceName,portName;
                    
                    //and now traverse the tree of the taskLocationNode
                    NodeList childrenOfTaskLocation = taskLocationNode.getChildNodes();
                    Node urlNode = childrenOfTaskLocation.item(0);
                    //jumping over plain text nodes
                    while (urlNode.getNodeType() != urlNode.ELEMENT_NODE)
                        urlNode = urlNode.getNextSibling();
                    String urlNodeName = urlNode.getNodeName();

                    if (debug)
                        out.println(urlNodeName);
                    
                    if(urlNodeName.equals("url"))
                    {
                        url=urlNode.getAttributes().getNamedItem("value").getNodeValue();
                    } else {
                        throw new RuntimeException("url not specified correctly");
                    }
                    
                    if (debug)
                        out.println(url);
                                        
                    Node namespaceNode = urlNode.getNextSibling();
                    while (namespaceNode.getNodeType() != urlNode.ELEMENT_NODE)
                        namespaceNode = namespaceNode.getNextSibling();
                    
                    if (debug)
                        out.println(namespaceNode.getNodeName());
                    
                    String namespaceNodeName = namespaceNode.getNodeName();
                    
                    if(namespaceNodeName.equals("namespace"))
                    {
                        namespace=namespaceNode.getAttributes().getNamedItem("value").getNodeValue();
                    } else {
                        throw new RuntimeException("namespace not specified correctly");
                    }
                    
                    if (debug)
                        out.println(namespace);
                                        
                    Node serviceNameNode = namespaceNode.getNextSibling();
                    while (serviceNameNode.getNodeType() != urlNode.ELEMENT_NODE)
                        serviceNameNode = serviceNameNode.getNextSibling();
                    
                    if (debug)
                        out.println(serviceNameNode.getNodeName());
                    
                    String serviceNameNodeName = serviceNameNode.getNodeName();
                    
                    if(serviceNameNodeName.equals("servicename"))
                    {
                        serviceName=serviceNameNode.getAttributes().getNamedItem("value").getNodeValue();
                    } else {
                        throw new RuntimeException("servicename not specified correctly");
                    }
                    
                    if (debug)
                        out.println(serviceName);
                    
                    Node portNameNode = serviceNameNode.getNextSibling();
                    while (portNameNode.getNodeType() != urlNode.ELEMENT_NODE)
                        portNameNode = portNameNode.getNextSibling();
                    
                    if (debug)
                        out.println(portNameNode.getNodeName());
                    String portNameNodeName = portNameNode.getNodeName();
                    
                    if(portNameNodeName.equals("portname"))
                    {
                        portName=portNameNode.getAttributes().getNamedItem("value").getNodeValue();
                    } else {
                        throw new RuntimeException("portname not specified correctly");
                    }
                    
                    if (debug)
                        out.println(portName);
                    
                    newTask.setURL(url);
                    newTask.setNamespace(namespace);
                    newTask.setServiceName(serviceName);
                    newTask.setPortName(portName);
                                        
                } else
                {
                    
                    //and now traverse the tree of the taskLocationNode
                    NodeList childrenOfTaskLocation = taskLocationNode.getChildNodes();
                    Node actualTaskLocationNode = childrenOfTaskLocation.item(0);
                    //jumping over plain text nodes
                    while (actualTaskLocationNode.getNodeType() != Node.ELEMENT_NODE)
                        actualTaskLocationNode = actualTaskLocationNode.getNextSibling();
                    String taskLocationType = actualTaskLocationNode.getNodeName();

                    if (debug)
                        out.println(taskLocationType);

                    int[] tempTaskLocation = new int[2];                                
                    if (taskLocationType.equals("one-anywhere")) {
                        tempTaskLocation[0] = ATaGTaskDeclaration.INSTANTIATION_ONE_ANYWHERE;
                        tempTaskLocation[1] = 0;//just like that
                    } else if ((taskLocationType.equals("one-on-node"))) {
                        tempTaskLocation[0] = ATaGTaskDeclaration.INSTANTIATION_ONE_ON_NODE_ID;
                        //set target NODE ID as the other element
                        tempTaskLocation[1] = Integer.parseInt(
                                actualTaskLocationNode.getAttributes().item(0).getNodeValue());
                        if (debug)
                            out.println(tempTaskLocation[1]);
                    } else if ((taskLocationType.equals("nodes-per-instance"))) {
                        tempTaskLocation[0] = ATaGTaskDeclaration.INSTANTIATION_NODES_PER_INSTANCE;
                        //set number of nodes per instance as the other element
                        tempTaskLocation[1] = Integer.parseInt(
                                actualTaskLocationNode.getAttributes().item(0).getNodeValue());
                        if (debug)
                            out.println(tempTaskLocation[1]);
                    } else if ((taskLocationType.equals("nodes-per-instance-fractional"))) {
                        tempTaskLocation[0] = ATaGTaskDeclaration.INSTANTIATION_NODES_PER_INSTANCE_FRACTIONAL;
                        //set denominator as the other element
                        tempTaskLocation[1] = Integer.parseInt(
                                actualTaskLocationNode.getAttributes().item(0).getNodeValue());
                        if (debug)
                            out.println(tempTaskLocation[1]);
                    } else if ((taskLocationType.equals("partition-per-instance"))) {
                        tempTaskLocation[0] = ATaGTaskDeclaration.INSTANTIATION_PARTITION_PER_INSTANCE;
                        //set number of regions per node as the other element
                        tempTaskLocation[1] = Integer.parseInt(
                                actualTaskLocationNode.getAttributes().item(0).getNodeValue());
                        if (debug)
                            out.println(tempTaskLocation[1]);
                    }
                
                    newTask.setLocation(tempTaskLocation);

                    // set needed ability attributes, if any.
                    Node abilityAttributeNode = actualTaskLocationNode.getNextSibling();
                    while (abilityAttributeNode.getNodeType() != Node.ELEMENT_NODE)
                        abilityAttributeNode = abilityAttributeNode.getNextSibling();
                    //this is the real ability attribute
                    if (debug)
                        out.println(abilityAttributeNode.getNodeName());
                    //and now traverse the tree of the taskLocationNode

                    String abilityAttributeNodeName = abilityAttributeNode.getNodeName();
                    // "set" comes after "ability" in the alphabet, hence use item(1)
                    String abilityString = abilityAttributeNode.getAttributes().item(0).getNodeValue();
                    
                    if (debug)
                        out.println(abilityString);

                    //splitting the abilityString with ","s
                    if (!(abilityString.equalsIgnoreCase("none"))) {
                        String[] abilityValue = abilityString.split(",");
                        for (String x : abilityValue) {
                            if (x.equalsIgnoreCase("GUI") &&
                                    tempFiringRule[0] == ATaGTaskDeclaration.FIRING_TRIGGERED) {
                                        newTask.setRunAtInit(false);
                            }                        
                            newTask.setNeededAttribute(new SetAttribute
                                (ATaGTaskDeclaration.ABILITY_ATTRIBUTE_NAME, abilityValue));
                        }
                    }

                    // ability set, now set region
                    Node regionAttributeNode = abilityAttributeNode.getNextSibling();
                    while (regionAttributeNode.getNodeType() != Node.ELEMENT_NODE)
                        regionAttributeNode = regionAttributeNode.getNextSibling();
                    //this is the real region attribute
                    if (debug)
                        out.println(regionAttributeNode.getNodeName());


                    String regionName = regionAttributeNode.getAttributes().item(0).getNodeValue();
                    if (debug)
                        out.println(regionName);
                    if (!(regionName.equalsIgnoreCase("none"))) {

                        newTask.setMyRegionName(regionName);
                    }
                }
                
                Node taskFaultToleranceNode = taskLocationNode.getNextSibling();
                while (taskFaultToleranceNode != null && taskFaultToleranceNode.getNodeType() != Node.ELEMENT_NODE){
                	taskFaultToleranceNode = taskFaultToleranceNode.getNextSibling();
                }
                if (taskFaultToleranceNode != null){
	                if (debug) out.println(taskFaultToleranceNode.getNodeName());
	                NamedNodeMap ftAttrs = taskFaultToleranceNode.getAttributes();
	                for (int i = 0; i < ftAttrs.getLength(); i++) {
	                    Attr attr = (Attr) ftAttrs.item(i);
	                    if (debug)
	                        out.println("Attr #" + i + " " + attr.getNodeName() + " is " + attr.getNodeValue());
	                }
	
	                if ( ftAttrs.item(0).getNodeValue().equals("replication") ){
	                	newTask.setFaultTolerance(ATaGTaskDeclaration.FAULTTOLERANCE_REPLICATION);
	                }
                }

                tList.add(newTask);

            }// parsing a non-text task node
        }//looking at kids of tasklist

        //task list populated. Now on to the the datalist

        //skip text type child nodes
        while (topLevelChildren.item(count).getNodeType() != Node.ELEMENT_NODE)
            count++;

        Node dataList = topLevelChildren.item(count++);
        if (debug)
            out.println(dataList.getNodeName());
        // now populate the data list
        ArrayList<ATaGDataItemDeclaration> dList = retProgram.getDataList();

        NodeList dataListChildren = dataList.getChildNodes();
        for (int dataCount = 0; dataCount < dataListChildren.getLength(); dataCount++) {
            Node tempDataNode = dataListChildren.item(dataCount);
            if (tempDataNode.getNodeType() != Node.ELEMENT_NODE) {
                //plain text. Ignore
                continue;
            } else {
                //parse this data item and insert it
                ATaGDataItemDeclaration newDataItem = new ATaGDataItemDeclaration();
                //fill in the details
                NamedNodeMap dataAttrs = tempDataNode.getAttributes();
                int len = dataAttrs.getLength();
                for (int i = 0; i < len; i++) {
                    Attr attr = (Attr) dataAttrs.item(i);
                    if (debug)
                        out.println("Attr #" + i + " " + attr.getNodeName() + " is " +
                                attr.getNodeValue());
                }

                newDataItem.setName(new String(dataAttrs.item(0).getNodeValue()));
                
                NodeList paramList=tempDataNode.getChildNodes();
                for (int paramCount = 0; paramCount < paramList.getLength(); paramCount++) {
                    Node paramNode = paramList.item(paramCount);
                    if (paramNode.getNodeName().equals("parameter")) {
                        //parse this parameter and insert it
                        NamedNodeMap paramAttributes = paramNode.getAttributes();
                        String name=paramAttributes.getNamedItem("name").getNodeValue();
                        String type=paramAttributes.getNamedItem("type").getNodeValue();                                                
                        if (debug)
                            out.println("Data item: " + newDataItem.getName() + 
                                ", Name: " + name + " , Type: " +type);
                        if(name!=null && type!=null)
                        {
                            String javaType = type;
                            if(javaDataTypeFromXmlType.containsKey(type))
                                javaType=javaDataTypeFromXmlType.get(type);
                            newDataItem.addParameter(name, javaType);
                        }
                    }
                }
                dList.add(newDataItem);

            }//if text or non-text node
        }//for


        //skip text type child nodes
        while (topLevelChildren.item(count).getNodeType() != Node.ELEMENT_NODE)
            count++;

        Node channelList = topLevelChildren.item(count++);
        if (debug)
            out.println(channelList.getNodeName());
        // now populate the channel list
        ArrayList<ScopedChannel> cList = retProgram.getChannelList();

        NodeList channelListChildren = channelList.getChildNodes();
        for (int channelCount = 0; channelCount < channelListChildren.getLength();
             channelCount++) {
            Node tempChannelNode = channelListChildren.item(channelCount);
            if (tempChannelNode.getNodeType() != Node.ELEMENT_NODE) {
                //plain text. Ignore
                continue;
            } else {
                //parse this data item and insert it
                ScopedChannel newChannel = new ScopedChannel();
                //fill in the details
                NamedNodeMap channelAttrs = tempChannelNode.getAttributes();
                int len = channelAttrs.getLength();


                String direction = channelAttrs.getNamedItem("direction").
                        getNodeValue();

                if (direction.equalsIgnoreCase("RPC")) {
                    newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_RPC);
                    String requestingtaskname = channelAttrs.getNamedItem("requestingtaskname").
                            getNodeValue();
                    String respondingtaskname = channelAttrs.getNamedItem("respondingtaskname").
                            getNodeValue();
                    newChannel.setTaskName(requestingtaskname + " " + respondingtaskname);                    
                    newChannel.setDataID(ScopedChannel.INVALID);                    
                } else if (direction.equalsIgnoreCase("request-response")) {
                    newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_REQUEST_RESPONSE);
                    String requestingtaskname = channelAttrs.getNamedItem("requestingtaskname").
                            getNodeValue();
                    String respondingtaskname = channelAttrs.getNamedItem("respondingtaskname").
                            getNodeValue();
                    newChannel.setTaskName(requestingtaskname + " " + respondingtaskname);

                    String requestdataname = channelAttrs.getNamedItem("requestdataname").
                            getNodeValue();
                    String respondsedataname = channelAttrs.getNamedItem("responsedataname").
                            getNodeValue();
                    newChannel.setDataName(requestdataname + " " + respondsedataname);

                    if (channelAttrs.getNamedItem("local").getNodeValue().equalsIgnoreCase("true"))
                        newChannel.setLocalFlag(true);
                    else
                        newChannel.setLocalFlag(false);

                    newChannel.setInterest(channelAttrs.getNamedItem("interest").getNodeValue());

                } else {

                    //the attributes are arranged alphabetically
                    newChannel.setDataName(new String(channelAttrs.item(0).getNodeValue()));

                    String tempInterest = channelAttrs.item(1).getNodeValue();
                    if (tempInterest.equals("TtoD")) {
                        newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_OUTPUT);
                    } else {
                        newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_INPUT);
                    }

                    newChannel.setInterest(new String(channelAttrs.item(2).getNodeValue()));

                    //set the local value
                    if (channelAttrs.item(3).getNodeValue().equalsIgnoreCase("true"))
                        newChannel.setLocalFlag(true);
                    else
                        newChannel.setLocalFlag(false);

                    newChannel.setTaskName(new String(channelAttrs.item(4).getNodeValue()));

                }
                cList.add(newChannel);
            }//if text or non-text node
        }//for
        //ATaGProgram ready to be "returned"
        out.println("Atag program fully parsed");
        return retProgram;
    }

    // for testing
    public static void main(String args[]) {
        String filename = new String("c:\\web\\atag\\traffic\\traffic.xml");
        DocumentBuilderFactory factory =
                DocumentBuilderFactory.newInstance();
        //factory.setValidating(true);
        //factory.setNamespaceAware(true);

        ATaGProgram retProgram = new ATaGProgram();

        try {
            DocumentBuilder builder = factory.newDocumentBuilder();

            ATaGParsingErrorHandler eh = new ATaGParsingErrorHandler();

            builder.setErrorHandler(eh);

            /*
            use the info in http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JAXPDOM8.html
            */
            document = builder.parse(new File(filename));


            // now do stuff with it
            try {
                Node n = document.getDocumentElement();
                //retProgram = parseATaGXML(n);
                print(n, System.out);

            } catch (Exception e) {
                e.printStackTrace();
            }


        } catch (SAXException sxe) {
            // Error generated during parsing)
            Exception x = sxe;
            if (sxe.getException() != null)
                x = sxe.getException();
            x.printStackTrace();
            /*
            System.out.println("Parsing failed. Document does not match DTD");
             */

        } catch (ParserConfigurationException pce) {
            // Parser with specified options can't be built
            pce.printStackTrace();

        } catch (IOException ioe) {
            // I/O error
            ioe.printStackTrace();
        }

        ATaGProgram ap = parseATaGProgram(filename);

        return;
    }

}//end of class ATaGParser


class ATaGParsingErrorHandler implements org.xml.sax.ErrorHandler {
    // ignore fatal errors (an exception is guaranteed)
    public void fatalError(SAXParseException exception)
            throws SAXException {
    }

    // treat validation errors as fatal
    public void error(SAXParseException e)
            throws SAXParseException {
        throw e;
    }

    // dump warnings too
    public void warning(SAXParseException err)
            throws SAXParseException {
        System.out.println("** Warning"
                + ", line " + err.getLineNumber()
                + ", uri " + err.getSystemId());
        System.out.println("   " + err.getMessage());
    }


}
